
var LiveRoom = {
    /**
     *  @param object
     *  {
     *  data: {
     *      serverDomain  String   请求的后台地址
     *      userID        String    用户ID
     *      userName      String    用户昵称
     *      sdkAppID      String    IM登录凭证
     *      accType       Int       账号集成类型
     *      userSig       String    IM签名
     *  }
     * success       function  成功回调
     * fail          function  失败回调
     * }
     *
     */
    login: function (object) {},

    /**
     * @param object
     * {
     * success       function  成功回调
     * fail          function  失败回调
     * }
     */
    logout: function (object) {},

    /**
     *  @param object
     *  {
     *      onGetPusherList         function 
     *          {
     *              roomID              String  房间号
     *              roomInfo            String  用户自定义信息
     *              mixedPlayURL        String  混流地址
     *              pushers: [
     *                  {
        *                  userID          String  用户ID
        *                  userName        String  用户昵称
        *                  userAvatar      String  用户头像
        *                  accelerateURL   String  加速流地址
     *                  }
     *              ]
     *          }
     *      onPusherJoin            function
     *          [
     *              {
     *                 userID          String  用户ID
     *                 userName        String  用户昵称
     *                 userAvatar      String  用户头像
     *                 accelerateURL   String  加速流地址        
     *             }
     *          ]
     *      onPusherQuit            function
     *          [
     *              {
     *                 userID          String  用户ID
     *                 userName        String  用户昵称
     *                 userAvatar      String  用户头像
     *                 accelerateURL   String  加速流地址        
     *             }
     *          ]
     *      onRoomClosed            function
     *          {
     *              roomID          String  房间号
     *          }
     *      onRecvRoomTextMsg       fuction
     *          {
     *              roomID          String  房间号
     *              userID          String  用户ID
     *              userName        String  用户昵称
     *              userAvatar      String  用户头像
     *              message         String  文本消息
     *          } 
     *      onRecvJoinPusherRequest fuction
     *          {
     *              userID          String  用户ID
     *              userName        String  用户昵称
     *              userAvatar      String  用户头像        
     *          }
     *      onKickOut               function    小主播被踢
     *          {
     *              roomID          String  被踢出的房间号
     *          }
     *      onRecvRoomCustomMsg     function
     *          {
     *              roomID          String  房间号
     *              userID          String  用户ID
     *              userName        String  用户昵称
     *              userAvatar      String  用户头像
     *              cmd             String  自定义命令
     *              message         String  文本消息
     *          } 
     *      onError                 function
     *          {
     *              errCode         Int     错误码
     *              errMsg          String  错误描述
     *          }
     *      onRecvC2CCustomMsg      fuction
     *          {
     *              userID          String  用户ID
     *              userName        String  用户昵称
     *              userAvatar      String  用户头像
     *              cmd             String  自定义命令
     *              message         String  文本消息
     *          }  
     *  }
     */
    setLiveRoomListener: function (object) {},

    /**
     * 创建房间（大主播）
     * @param object
     * {
     *  data: {
     *     roomInfo:    String  用户自定义数据，作为房间信息会在getRoomList函数返回 
     *  }
     * success       function(ret)  成功回调
     *      ret: {
     *          roomID
     *      }
     * fail          function  失败回调
     * }
     */

    createRoom: function (object) {},

    /**
     * 进入房间（小主播）
     * @param object
     * {
     *  data: {
     *      roomID:     String
     *      divId:      String  播放画面所在div
     *  }
     * success       function  成功回调
     * fail          function  失败回调
     * }
     */
    enterRoom: function (object) {},

    /**
     * @param object
     * {
     * success       function  成功回调
     * fail          function  失败回调
     * }
     */
    exitRoom: function (object) {},

    /**
     * @param object
     * {
     *  data: {
     *      index       Int
     *      count       Int
     *  }
     * success       function  成功回调
     * fail          function  失败回调
     * }
     */
    getRoomList: function (object) {
        
    },

    /**
     * @param object
     * {
     *  data: {
     *      roomID      String      房间号
     *  }
     * success      function  成功回调
     * fail         function  失败回调
     * }
     */
    getAudienceList: function (object) {

    },

    /**
     * @param object
     * {
     * success       function  成功回调
     * fail          function  失败回调
     * }
     */ 
    joinPusher: function (object) {},
    
    /**
     * @param object
     * {
     * success       function  成功回调
     * fail          function  失败回调
     * }
     */ 
    quitPusher: function (object) {},

    /**
     * @param object
     * {
     * data: {
     *      timeout:    Int     超时时间（MS）
     * }
     * success       function  成功回调
     * fail          function  失败回调
     * }
     */
    requestJoinPusher: function (object) {},

    /**
     * @param object
     * {
     * data: {
     *      userID:    String   申请连麦的用户ID
     * }
     * }
     */
    acceptJoinPusher: function (object) {},

    /**
     * @param object
     * {
     * data: {
     *      userID:     String   申请连麦的用户ID
     *      reason:     String  拒绝理由
     * }
     * }
     */
    rejectJoinPusher: function (object) {},

    /**
     * @param object
     * {
     * data: {
     *      userID:    String   连麦的小主播ID
     * }
     * success       function  成功回调
     * fail          function  失败回调
     * }
     */
    kickoutSubPusher: function (object) {},

    /**
     * @param object
     * {
     *  data: {
     *      divId:      String  推流预览画面所在divId
     *      cameraId:   String  摄像头ID
     *  }
     * success       function  成功回调
     * fail          function  失败回调
     * }
     */
    startLocalPreview: function (object) {},

    /**
     * @param none
     */
    stopLocalPreview: function () {},

    /**
     * @param object
     * {
     *  data: {
     *      cameraId:      String  摄像头ID
     *  }
     * }
     */
    switchCamera: function (object) {},

    /**
     * @param object
     * {
     *  data: {
     *      divId:      String  播放画面所在的divId
     *      userID:     String  要播放的成员ID
     *  }
     * success       function  成功回调
     * fail          function  失败回调
     * }
     */
    addRemoteView: function (object) {},

    /**
     * @param object
     * {
     *  data: {
     *      userID:     String  要停止播放的成员ID
     *  }
     * success       function  成功回调
     * fail          function  失败回调
     * }
     */
    deleteRemoteView: function (object) {},

    /**
     * @param object
     * {
     *  data: {
     *      message:     String     发送的文本消息
     *  }
     * success       function  成功回调
     * fail          function  失败回调
     * }
     */
    sendRoomTextMsg: function (object) {},

    /**
     * @param object
     * {
     *  data: {
     *      cmd:         String     自定义命令
     *      message:     String     发送的文本消息
     *  }
     * success       function  成功回调
     * fail          function  失败回调
     * }
     */
    sendRoomCustomMsg: function (object) {},

    /**
     * @param object
     * {
     *  data: {
     *      style:              Int         美颜风格.三种美颜风格：0 ：光滑  1：自然  2：朦胧
     *      beautyLevel:        Int         美颜级别取值范围 1 ~ 9； 0 表示关闭，1 ~ 9值越大，效果越明显，默认为0
     *      whiteningLevel:     Int         美白级别取值范围 1 ~ 9； 0 表示关闭，1 ~ 9值越大，效果越明显，默认为0
     *  }
     * }
     */
    setBeautyFilter: function (object) {},

    /**
     * @param object
     * {
     *  data: {
     *      quality            Int
     *      ratioType          Int
     *  }
     * }
     */
    setVideoQuality: function (object) {}
}

LiveRoom = (function () {

    var accountInfo = {
        userID: 'yaobo',			// 用户ID
        userName: '',		   // 用户昵称
        userAvatar: '',		// 用户头像URL
        userSig: '',		// IM登录凭证
        sdkAppID: '',		// IM应用ID
        accountType: '',	// 账号集成类型
        accountMode: 0,		//帐号模式，0-表示独立模式，1-表示托管模式
        pushURL: '',        //推流地址
        isCreator: false,    //是否是房间创建者
        previewDivId: "",
        token: "",
    },
    // 房间信息
    roomInfo = {
        roomID: '',			// 视频位房间ID
        roomInfo: '',		// 自定义信息
        mixedPlayURL: '', 	// 混流地址
        pushers: [],		// 当前用户信息accelerateURL userAvatar, userID, userName
        isDestory: true,// 是否已解散
        roomCreator: '',    //房间创建者的userID
    },

    event = {
        onGetPusherList: function () {},		// 初始化成员列表
        onPusherJoin: function () {},			// 进房通知
        onPusherQuit: function () {},			// 退房通知
        onRoomClosed: function() {},			// 群解散通知
        onRecvRoomTextMsg: function() {},		// 消息通知
        onRecvJoinPusherRequest: function() {}, //大主播收到小主播连麦请求通知
        onKickOut: function() {}, //小主播被踢通知
        onRecvRoomCustomMsg: function() {}, //自定义消息通知
        onSketchpadData: function(){},
        onError: function() {}, //错误回调
        onRecvC2CCustomMsg: function() {},
    },
    
    VIDEO_QUALITY = {
        STANDARD: 1,    //480x272 or 272x480
        HIGH: 2,    //640x360 or 360x640
        SUPER: 3,    //960x540 or 540x960
        LINKMIC_MAIN_PUSHER: 4, //大主播连麦
        LINKMIC_SUB_PUSHER: 5  //小主播连麦
    },
    
    RATIO_TYPE = {
        TYPE_WIDE: 0,   //屏幕比例16:9
        TYPE_HIGH: 1    //屏幕比例9:16
    };



    var serverDomain = '', heart = '', viewTag = 0, hasRecvPushBeginEvent = false, startPushCallback = null, requestJoinCallback = null, gTimeoutID = null, bigAnchorStreamID = '', userIDPrefix = 'liteav_';
    var videoQuality = VIDEO_QUALITY.HIGH, ratioType = RATIO_TYPE.TYPE_WIDE;
    var gMergeStreams = [];

    function login (object) {
        if (!object || !object.data.serverDomain) {
            console.error("init参数错误");
            object.fail && object.fail(-9999, "init参数错误");
            return;
        }

        serverDomain = object.data.serverDomain;
        accountInfo.userID = object.data.userID;
        accountInfo.userSig = object.data.userSig;
        accountInfo.sdkAppID = object.data.sdkAppID;
        accountInfo.accountType = object.data.accType;
        accountInfo.userName = object.data.userName || accountInfo.userID;
        accountInfo.userAvatar = object.userAvatar || "123";
        //accountInfo.previewDivId = object.data.divId
       
        var args = {
            userID: accountInfo.userID,
            accountType: accountInfo.accountType,
            sdkAppID: accountInfo.sdkAppID,
            userSig: accountInfo.userSig
        }
        //roomservice登录
        request({
            url: 'login' + '?' + formatParams(args),
            data: {},
            success: function(ret) {
                if(ret.data.code) {
                    console.log('登录失败');
                    object.fail && object.fail({errCode: ret.data.code, errMsg: 'roomservice登录失败:' + ret.data.message + '[' + ret.data.code + ']'});
                    return;
                }
                accountInfo.token = ret.data.token;
                //IM登录
                loginIM({
                    roomID: roomInfo.roomID,
                    success: function(ret) {
                        object.success && object.success(accountInfo.userID)
                    },
                    fail: function(ret) {
                        object.fail && object.fail({errCode: -1, errMsg: 'IM登录失败'});
                    }
                });;
            },
            fail: function(ret) {
                console.log('登录请求发送失败');
                object.fail && object.fail(ret);
            }
        });
    }

    function logout (object) {
       exitRoom({});
       var args = {
           userID: accountInfo.userID,
           token: accountInfo.token
       }
        request({
            url: 'logout?' + formatParams(args),
            success: object.success || function(ret) {},
            fail: object.fail || function(ret) {}
        });
        webimhandler.logout();
    }

    function setLiveRoomListener (object) {
        if (!object) {
            console.error('setListener参数错误', object);
            return;
        }
    
        event.onGetPusherList = object.onGetPusherList || function () {};
        event.onPusherJoin = object.onPusherJoin || function () {};
        event.onPusherQuit = object.onPusherQuit || function () {};
        event.onRoomClosed = object.onRoomClosed || function () {};
        event.onRecvRoomTextMsg = object.onRecvRoomTextMsg || function () {};
        event.onRecvJoinPusherRequest = object.onRecvJoinPusherRequest || function () {};
        event.onKickOut = object.onKickOut || function () {};
        event.onRecvRoomCustomMsg = object.onRecvRoomCustomMsg || function () {};
        event.onError = object.onError || function () {};
        event.onSketchpadData = object.onSketchpadData || function(){};
        event.onRecvC2CCustomMsg = object.onRecvC2CCustomMsg || function() {};
    }

    /**
     * 调用该函数前需要先调用startLocalPreview进行预览 
     * @param {Object} object
     *       
     */
    function createRoom (object) {
        roomInfo.isDestory = false;
        accountInfo.isCreator = true;
        var args = {
            userID: accountInfo.userID,
            token: accountInfo.token
        }
        //1、在demo层调用startLocalPreview开启预览
        //2、获取推流地址
        console.log("获取推流地址");
        request({
            url: 'get_push_url?' + formatParams(args),
            data: {
                userID: accountInfo.userID
            },
            success: function (ret) {
               if (ret.data.code) {
                   console.log('获取推流地址失败', ret);
                   object.fail && object.fail({errCode: ret.data.code, errMsg: '获取推流地址失败:' + ret.data.message +  + '[' + ret.data.code + ']'});
                   return;
               }
               console.log("获取推流地址成功，开始推流:", JSON.stringify(ret));
               accountInfo.pushURL = ret.data.pushURL;
               hasRecvPushBeginEvent = false;
               //3、开始推流
               startPush({
                   success: function (ret) {
                        //推流过程中，可能会重复收到PUSH_EVT_PUSH_BEGIN事件，onSuccess可能会被回调多次，如果已经回调过则返回
                        if (hasRecvPushBeginEvent) {
                            return;
                        }
                        hasRecvPushBeginEvent = true;
                        console.log("推流成功，开始创建房间");
                       //4、推流成功后，请求CGI:create_room，获取roomID
                       doCreateRoom({
                           data: object.data,
                           success: function (ret) {
                                roomInfo.roomID = ret.data.roomID;
                                roomInfo.roomInfo = object.data.roomInfo || '';
                                roomInfo.roomCreator = accountInfo.userID;
                                console.log("创建房间成功，向房间添加推流信息");
                                //5、创建房间成功后，请求CGI：add_pusher，加入房间
                                addPusher({
                                    success: function(ret) {
                                        // 开始心跳，roomservice后台会通过心跳来检查当前推流是否还存在
                                        heart = true;
                                        pusherHeartBeat(1);
                                        console.log("添加推流信息成功，加入IM群组");
                                        //6、加入房间成功后，加入IM群组
                                        webimhandler.applyJoinBigGroup(roomInfo.roomID, function(ret) {
                                            if (ret.errCode) {
                                                console.log("进IM群失败");
                                                object.fail && object.fail({errCode: ret.errCode, errMsg: "进IM群失败:" + '[' + ret.errCode + ']'});
                                                return;
                                            }

                                            console.log("加入IM群组成功");
                                            object.success && object.success({
                                                roomID: roomInfo.roomID,
                                                code: 0,
                                                message: ""
                                            })

                                        }, 0);
                                    },
                                    fail: object.fail
                                })
                           },
                           fail: object.fail
                       }) 
                   },
                   fail: object.fail
               });

            },
            fail: function (ret) {
                console.log('获取推流地址请求失败', ret);
                object.fail && object.fail(ret);
            }
        });
    }

    function enterRoom (object) {
        console.log('enterRoommmmmmm ', object.data)
        var args = {
            userID: accountInfo.userID,
            token: accountInfo.token
        }
        //获取房间信息
        request({
            url: 'get_pushers?' + formatParams(args),
            data: {
                roomID: object.data.roomID
            },
            success: function (ret) {
                if (ret.data.code) {
                    console.log('请求CGI:get_pushers失败', ret);
                    object.fail && object.fail({errCode: ret.data.code, errMsg: '请求CGI:get_pushers失败:' + ret.data.message +  + '[' + ret.data.code + ']'});
                    return;
                }
                roomInfo.roomID = ret.data.roomID;
                roomInfo.roomInfo = ret.data.roomInfo;
                roomInfo.roomCreator = ret.data.roomCreator;
                roomInfo.mixedPlayURL = ret.data.mixedPlayURL;
                roomInfo.pushers = ret.data.pushers;

                //将流地址改为rtmp头的流地址
                var prevIndex = roomInfo.mixedPlayURL.indexOf('//', 0);
                var suffIndex = roomInfo.mixedPlayURL.indexOf('.flv', 0);
                roomInfo.mixedPlayURL = prevIndex>0&&suffIndex>0 ? ('rtmp:' + roomInfo.mixedPlayURL.substring(prevIndex, suffIndex)) : roomInfo.mixedPlayURL;
                console.log('混流地址:', roomInfo.mixedPlayURL);

                //加入IM群
                webimhandler.applyJoinBigGroup(roomInfo.roomID, function(ret) {
                    if (ret.errCode) {
                        console.log("进IM群失败");
                        object.fail && object.fail({errCode: ret.errCode, errMsg: "进IM群失败:" + '[' + ret.errCode + ']'});
                        return;
                    }

                    //播放直播流
                    startPlay({
                        data: {
                            divId: object.data.divId,
                            userID: roomInfo.roomCreator,
                            playUrl: roomInfo.mixedPlayURL,
                            playType: 0
                        }
                    });

                    //观众进房通知
                    var userInfo = {
                        userName: accountInfo.userName,
                        userAvatar: accountInfo.userAvatar
                    }
                    addAudience({
                        data: {
                            userID: accountInfo.userID,
                            roomID: object.data.roomID,
                            userInfo: JSON.stringify(userInfo)
                        }
                    })

                    object.success && object.success({
                        data: {
                            roomID: roomInfo.roomID
                        },
                        code: 0,
                        message: ""
                    })

                }, 0); 
            },
            fail: object.fail
        });
    }

    function exitRoom (object) {
        //停止心跳
        stopPusherHeartBeat();

        //退出IM群
        webimhandler.quitBigGroup();

        //停止推流
        stopLocalPreview();

        //停止普通流播放
        var livePlayer = document.getElementById(userIDPrefix + roomInfo.roomCreator);
        if (livePlayer) {
            deleteRemoteView({
                data: {
                    userID: roomInfo.roomCreator
                }
            });
        }

        //停止所有加速流播放
        stopAllAccPlayers(); 

        //告知roomservice删除推流
        var args = {
            userID: accountInfo.userID,
            token: accountInfo.token
        }
        if (roomInfo.roomID) {
            request({
                url: 'delete_pusher?' + formatParams(args),
                data: {
                    roomID: roomInfo.roomID,
                    userID: accountInfo.userID
                },
                success: function(ret) {
                    if(ret.data.code) {
                        console.log('退出推流失败:', JSON.stringify(ret));
                        object.fail && object.fail({
                            errCode: ret.data.code,
                            errMsg: ret.data.message + '[' + ret.data.code + ']'
                        });
                        return;
                    }
                    console.log('退出推流成功');
                    object.success && object.success({});
                },
                fail: function(ret) {
                    console.log('退出推流失败:', JSON.stringify(ret));
                    object.fail && object.fail({
                        errCode: ret.errCode || -1,
                        errMsg: ret.errMsg || '退出推流失败'
                    });
                }
            });
        }

        //观众退房通知
        delAudience({
            data: {
                userID: accountInfo.userID,
                roomID: roomInfo.roomID
            },
            success: function(ret) {},
            fail: function(ret) {},

        })

        if (roomInfo.roomCreator == accountInfo.userID && roomInfo.roomID) {
            request({
                url: 'destroy_room?' + formatParams(args),
                data: {
                    userID: accountInfo.userID,
                    roomID: roomInfo.roomID
                },
                success: function (ret) {

                },
                fail: function (ret) {

                }
            })
        }

        roomInfo.roomID = '';
        roomInfo.pushers = [];
        roomInfo.isDestory = true;
        roomInfo.mixedPlayURL = "";
        roomInfo.roomName = "";
        accountInfo.pushURL = "";
        accountInfo.isCreator = false;
    }

    function getRoomList (object) {
        console.log('-----getRoomList------');
        var args = {
            userID: accountInfo.userID,
            token: accountInfo.token
        } 
        request({
            url: 'get_room_list?' + formatParams(args),
            data: {
                index: object.data.index,
                cnt: object.data.count
            },
            success: function (ret) {
                if(ret.data.code) {
                    console.log('获取房间列表失败:', JSON.stringify(ret));
                    object.fail && object.fail({
                        errCode: ret.data.code,
                        errMsg: ret.data.message + '[' + ret.data.code + ']'
                    });
                    return;
                }
                object.success && object.success(ret);
            },
            fail: object.fail
        });
    }

    function getAudienceList(object) {
        var args = {
            userID: accountInfo.userID,
            token: accountInfo.token
        }
        request({
            url: 'get_audiences?' + formatParams(args),
            data: {
                roomID: object.data.roomID
            },
            success: function (ret) {
                console.log('获取到观众列表:', JSON.stringify(ret));
                if(ret.data.code) {
                    console.log('获取房间观众失败:', JSON.stringify(ret));
                    object.fail && object.fail({
                        errCode: ret.data.code,
                        errMsg: ret.data.message + '[' + ret.data.code + ']'
                    });
                    return;
                }
                var audienceList = [];
                if (ret.data.audiences && ret.data.audiences.length > 0) {
                    ret.data.audiences.forEach(function (val) {
                        var userInfo = JSON.parse(val.userInfo);
                        var audience = {
                            userID: val.userID,
                            userName: userInfo.userName,
                            userAvatar: userInfo.userAvatar
                        }
                        audienceList.push(audience);
                    });
                }
                object.success && object.success({
                    data: {
                        code: 0,
                        message: '',
                        audiences: audienceList
                    }
                });
            },
            fail: object.fail
        });
    }

    function joinPusher (object) {
        //1、结束播放大主播的普通流，改为播放加速流
        var livePlayer = document.getElementById(userIDPrefix + roomInfo.roomCreator);
        if (livePlayer) {
            livePlayer.stopPlay();
            if (roomInfo.pushers && roomInfo.pushers.length > 0) {
                roomInfo.pushers.forEach(function (pusher) {
                    if (roomInfo.roomCreator == pusher.userID) {
                        livePlayer.startPlay(pusher.accelerateURL, 1);
                    }
                });
            }
        }
       
        var args = {
            userID: accountInfo.userID,
            token: accountInfo.token
        }
        //2、获取推流地址
        request({
            url: 'get_push_url?' + formatParams(args),
            data: {
                userID: accountInfo.userID
            },
            success: function (ret) {
               if (ret.data.code) {
                   console.log('获取推流地址失败', ret);
                   object.fail && object.fail({errCode: ret.data.code, errMsg: '获取推流地址失败:' + ret.data.message +  + '[' + ret.data.code + ']'});
                   return;
               }
               accountInfo.pushURL = ret.data.pushURL;
               hasRecvPushBeginEvent = false;
               //3、开始推流
               startPush({
                   success: function (ret) {
                        //推流过程中，可能会重复收到PUSH_EVT_PUSH_BEGIN事件，onSuccess可能会被回调多次，如果已经回调过则返回
                        if (hasRecvPushBeginEvent) {
                            return;
                        }
                        hasRecvPushBeginEvent = true;
                        //小主播，修改quality
                        setVideoQualityImpl(VIDEO_QUALITY.LINKMIC_SUB_PUSHER, ratioType);
                        //4、创建房间成功后，请求CGI：add_pusher，加入房间
                        addPusher({
                            success: function(ret) {
                                //开始心跳，roomservice后台会通过心跳来检查当前推流是否还存在
                                heart = true;
                                pusherHeartBeat(1);
                                object.success && object.success(ret);
                            },
                            fail: object.fail
                        });
                   },
                   fail: object.fail
               });

            },
            fail: function (ret) {
                console.log('获取推流地址请求失败', ret);
                object.fail && object.fail(ret);
            }
        });

        getPushers({
           data: {
               roomID: roomInfo.roomID
           },
           success: function(ret) {
            if (ret.data.code) {
                console.log('获取推流信息失败', ret);
                return;
            }

            //回调房间信息给demo层
            console.log('推流信息:', JSON.stringify(ret.data));
            event.onGetPusherList && event.onGetPusherList(ret.data);
           },
           fail: function(ret) {}
        })
    }

    function quitPusher (object) {
        //1、停止本地推流
        stopLocalPreview();

        //2. 将大主播的加速流改为普通流，并结束其他加速流的播放
        var player = document.getElementById(userIDPrefix + roomInfo.roomCreator);
        if (player) {
            player.stopPlay();
            player.startPlay(roomInfo.mixedPlayURL, 0);
        }
        if (roomInfo.pushers && roomInfo.pushers.length > 0) {
            roomInfo.pushers.forEach(function (pusher) {
                if (pusher.userID != roomInfo.roomCreator) {
                    deleteRemoteView({
                        data: {
                            userID: pusher.userID
                        }
                    });
                }
            });
        }

        //3、结束心跳
        stopPusherHeartBeat();

        //4、将自己从推流列表中删除
        var args = {
            userID: accountInfo.userID,
            token: accountInfo.token
        }
        request({
            url: 'delete_pusher?' + formatParams(args),
            data: {
                roomID: roomInfo.roomID,
                userID: accountInfo.userID
            },
            success: function (ret) {
                if (ret.data.code) {
                    console.log('delete_pusher失败', ret);
                    object.fail && object.fail({errCode: ret.data.code, errMsg: 'delete_pusher失败:' + ret.data.message +  + '[' + ret.data.code + ']'});
                    return;
                } 
                object.success && object.success();
            },
            fail: object.fail
        });

    }

    var hasSendRequestJoin = false;
    function requestJoinPusher (object) {
        var body = {
            cmd: 'linkmic',
            data: {
                type: 'request',
                roomID: roomInfo.roomID,
                userID: accountInfo.userID,
                userName: accountInfo.userName,
                userAvatar: accountInfo.userAvatar
            }
        }
        if(hasSendRequestJoin == true){
            return;
        }
        hasSendRequestJoin=true;
        
        requestJoinCallback = function(ret) {
            
            if(hasSendRequestJoin == false){
                return;
            }

            hasSendRequestJoin = false;
            if (gTimeoutID) {
                clearTimeout(gTimeoutID);
                gTimeoutID = null;
            }
            if (ret.errCode) {
                object.fail && object.fail(ret);
            } else {
                object.success && object.success(ret);
            }
            requestJoinCallback = null;
        }

        gTimeoutID = setTimeout(function () {
            gTimeoutID = null;
            console.error('申请连麦超时:', JSON.stringify(object.data));
            requestJoinCallback && requestJoinCallback({
                errCode: -999,
                errMsg: '申请加入连麦超时'
            });
        }, object.data.timeout);

        var msg = {
            data: JSON.stringify(body)
        }
        webimhandler.sendC2CCustomMsg(roomInfo.roomCreator, msg, function (ret) {

            if (ret && ret.errCode) {
                console.log('请求连麦失败:', JSON.stringify(ret));
                requestJoinCallback && requestJoinCallback(ret);
                return;
            }
        });


    }

    function acceptJoinPusher (object) {
        var body = {
            cmd: 'linkmic',
            data: {
                type: 'response',
                result: 'accept',
                message: '',
                roomID: roomInfo.roomID
            }
        }

        var msg = {
            data: JSON.stringify(body)
        }
        webimhandler.sendC2CCustomMsg(object.data.userID, msg, function (ret) {});
    }

    function rejectJoinPusher (object) {
        var body = {
            cmd: 'linkmic',
            data: {
                type: 'response',
                result: 'reject',
                message: object.data.reason || '',
                roomID: roomInfo.roomID
            }
        }

        var msg = {
            data: JSON.stringify(body)
        }
        webimhandler.sendC2CCustomMsg(object.data.userID, msg, function (ret) {});
    }

    function kickoutSubPusher (object) {
        var body = {
            cmd: 'linkmic',
            data: {
                type: 'kickout',
                roomID: roomInfo.roomID
            }
        }

        var msg = {
            data: JSON.stringify(body)
        }
        webimhandler.sendC2CCustomMsg(object.data.userID, msg, function (ret) {
            if (ret && ret.errCode==0) {
                object.success && object.success(ret);
            } else {
                object.fail && object.fail(ret);
            }
        });
    }

    /**
     * 开始本地画面预览
     * @param object
     * object.data.divId      本地画面区域div控件id
     * object.data.cameraId   摄像头Id
     * object.success    成功回调
     * object.fail       失败回调
     */
    function startLocalPreview (object) {
        
        var livePusher = getLivePusher();
        if (object.data.divId && object.data.divId != accountInfo.previewDivId) {

            if (livePusher)
                livePusher.parentNode.removeChild(livePusher);
            accountInfo.previewDivId = object.data.divId;
            livePusher = getLivePusher();
        }
        if (!livePusher) {
            console.error("无法获取pusher对象，请检查divId是否存在或者ActiveX插件是否被加载");
            object.fail && object.fail({
                errCode: -999,
                errMsg: '无法获取pusher对象，请检查divId是否存在或者ActiveX插件是否被加载'
            });
            return;
        }

        var cameraId = 0;
        if ( typeof(object.data.cameraId) == "undefined") {
            var cameras = getCameras({
                data: {
                    previewDivId: object.data.divId
                }
            });
            console.log('cameras: ', JSON.stringify(cameras));
            if (cameras.camera_cnt > 0) {
                cameraId = cameras.cameralist[0].id;
            }
            else {
                object.fail && object.fail({code:-1, msg:"没有可用的摄像头"});
                return;
            }
        }
        else {
            cameraId = object.data.cameraId;
        }
        var containDiv = document.getElementById(accountInfo.previewDivId)
        // containDiv.parentNode.attachEvent("onresize", function (ev) {
        //     var viewDiv = document.getElementById(accountInfo.previewDivId);
        //     var width = viewDiv.offsetWidth;
        //     var height = viewDiv.offsetHeight;
        //     var livePusher = document.getElementById(accountInfo.userID);
        //     if (livePusher) {
        //         livePusher.setAttribute("width", width.toString());
        //         livePusher.setAttribute("height", height.toString());
        //         livePusher.setRenderWndSize(width, height);
        //     }
        // });
        if (containDiv) {
            livePusher.setRenderWndSize(containDiv.offsetWidth, containDiv.offsetHeight);
        }
        livePusher.setPusherEventCallBack(onPushEvent, parseInt(cameraId));
        livePusher.switchCamera(cameraId);
        livePusher.startCameraPreview();
        livePusher.startAudioCapture();
        setVideoQualityImpl(videoQuality, ratioType);
        object.success && object.success();
    }

    function stopLocalPreview () {
        var livePusher = getLivePusher(); 
        if (livePusher) {
            livePusher.stopPush();
            livePusher.stopPreview();
            livePusher.parentNode.removeChild(livePusher);
        }
    }


    function switchCamera (object) {
        var livePusher = getLivePusher();
        if (livePusher) {
            livePusher.switchCamera(object.data.cameraId);
        }
    }

    /**
     * 播放指定userID的视频
     * @param object
     * object.data.divId    播放的视频区域div控件id
     * object.data.userID   要播放的成员的id
     * object.success       成功回调
     * object.fail          失败回调
     */
    function addRemoteView (object) {
        var hasUserId = false;
        roomInfo.pushers.forEach(function (value) {
            if (value.userID == object.data.userID) {
                hasUserId = true;
                //播放加速直播流
                startPlay({
                    data: {
                        divId: object.data.divId,
                        userID: value.userID,
                        playUrl: value.accelerateURL,
                        playType: 1
                    }
                });
                object.success && object.success();
                return;
            }
        });
    
        if (hasUserId)
            return;
        console.error("addRemoteView.can't find userID:" + object.data.userID);
        object.fail && object.fail({
            errCode: -999,
            errMsg:"找不到userID:"+object.data.userID
        });
    }

    /**
     * 停止播放指定userID的视频
     * @param object
     * object.data.userID     要停止播放的成员的id
     * object.success    成功回调
     * object.fail       失败回调
     */
    function deleteRemoteView (object) {
        stopPlay(object);
    }

    function switchToBackground (object) {}
    function switchToForeground (object) {}
    function setMicVolume (object) {}
    function setMute (object) {}

    function sendRoomTextMsg (object) {
        if(!object || !object.data.msg || !object.data.msg.replace(/^\s*|\s*$/g, '')) {
            console.log('sendRoomTextMsg参数错误', JSON.stringify(object));
            return;
        }
        webimhandler.sendCustomMsg({
            data: '{"cmd":"CustomTextMsg","data":{"nickName":"'+accountInfo.userName+'","headPic":"'+accountInfo.userAvatar+'"}}',
            text: object.data.msg
        },function() {
            object.success && object.success();
        });
    }

    function sendRoomCustomMsg(object) {
        if(!object || !object.data.msg || !object.data.msg.replace(/^\s*|\s*$/g, '')) {
            console.log('sendRoomTextMsg参数错误',object);
            return;
        }
        webimhandler.sendCustomMsg({
            data: '{"cmd":"CustomCmdMsg","data":{"nickName":"'+accountInfo.userName+'","headPic":"'+accountInfo.userAvatar+'","cmd":"'+object.data.cmd+'","msg":"'+object.data.message+'"}}',
        },function() {
            object.success && object.success();
        });
    }

    function sendSketchpadData(object) {
        console.log('发送白板数据函数被调用')
        webimhandler.sendSketchpadData(object)
    }

    function setCustomInfo (object) {}
    function decCustomInfo (object) {}
    function incCustomInfo (object) {}

    function setBGMVolume (object) {}
    function setBGMNofify (object) {}
    function getMusicDuration (object) {}
    function playBGM (object) {}
    function stopBGM (object) {}
    function pauseBGM (object) {}
    function resumeBGM (object) {}

    function setBeautyFilter (object) {
        var livePusher = getLivePusher();
        livePusher.setBeautyStyle(object.data.style, object.data.beautyLevel, object.data.whitenessLevel);
    }

    function setVideoQuality (object) {
        if (object.data && object.data.quality) {
            videoQuality = object.data.quality;
        }
        if (object.data && object.data.ratioType) {
            ratioType = object.data.ratioType
        }
        setVideoQualityImpl(videoQuality, ratioType);
    }
    
    function setVideoQualityImpl(quality, type) {
        var livePusher = getLivePusher();
        if (livePusher) {
            console.log("调整视频质量:" + quality + ":" + type);
            livePusher.setStreamQualityParamPreset(quality);
            switch(quality) {
                case VIDEO_QUALITY.HIGH:
                    if (type != RATIO_TYPE.TYPE_WIDE) {
                        // livePusher.setVideoResolution(52) //480x640
                        livePusher.setVideoResolution(203) //360x640
                    } else {
                        livePusher.setVideoResolution(103) //640x360
                    }
                    break;
                case VIDEO_QUALITY.SUPER:
                    if (type != RATIO_TYPE.TYPE_WIDE) {
                        // livePusher.setVideoResolution(53) //720x960
                        livePusher.setVideoResolution(204) //540x960
                    } else {
                        livePusher.setVideoResolution(104) //960x540
                    }
                    break;
                default:
                    if (type != RATIO_TYPE.TYPE_WIDE) {
                        // livePusher.setVideoResolution(51) //360x480
                        livePusher.setVideoResolution(202) //272x480
                    } else {
                        livePusher.setVideoResolution(102) //480x272
                    }
                    break;
            }
        }
    }

    function setZoom (object) {}
    function setMirror (object) {}
    function setExposureCompensation (object) {}
    function setRenderRotation (object) {}
    function setFilter (object) {}
    function setMotionTmpl (object) {}
    function setGreenScreenFile (object) {}
    function setEyeScaleLevel (object) {}
    function setFaceSlimLevel (object) {}
    function setFaceVLevel (object) {}
    function setSpecialRatio (object) {}
    function setFaceShortLevel (object) {}
    function setChinLevel (object) {}
    function setNoseSlimLevel (object) {}
    function setReverb (object) {}
    function setPauseImage (object) {}

    /*****************************************************************
     * 以下是私有函数
     *****************************************************************/

     //观众进房时，向后台发送进房通知
     function addAudience(object) {
        var args = {
            userID: accountInfo.userID,
            token: accountInfo.token
        };

        request({
            url: 'add_audience?' + formatParams(args),
            data: {
                userID: accountInfo.userID,
                roomID: object.data.roomID,
                userInfo: object.data.userInfo
            },
            success: function (ret) {
                if (ret.data.code) {
                    console.log('增加观众请求失败', ret);
                    object.fail && object.fail({errCode: ret.data.code, errMsg: '增加观众请求失败:' + ret.data.message +  + '[' + ret.data.code + ']'});
                    return;
                }
                object.success && object.success(ret);
            },
            fail: object.fail
        });
     }

     //观众退房时，向后台发送退房通知
     function delAudience(object) {
        var args = {
            userID: accountInfo.userID,
            token: accountInfo.token
        };

        request({
            url: 'delete_audience?' + formatParams(args),
            data: {
                userID: accountInfo.userID,
                roomID: object.data.roomID
            },
            success: function (ret) {
                if (ret.data.code) {
                    console.log('减少观众请求失败', ret);
                    object.fail && object.fail({errCode: ret.data.code, errMsg: '减少观众请求失败:' + ret.data.message +  + '[' + ret.data.code + ']'});
                    return;
                }
                object.success && object.success(ret);
            },
            fail: object.fail
        });
     }

    //开始播放流
    function startPlay(object) {

        var parentView = document.getElementById(object.data.divId);
        if (!parentView) {
            console.error("没有获取到拉流divID：", object.data.divId);
            return;
        }
        var width = parentView.offsetWidth;
        var height = parentView.offsetHeight;

        var html = '<object ID=' + userIDPrefix + object.data.userID.toString() + ' CLASSID="CLSID:99DD15EF-B353-4E47-9BE7-7DB4BC13613C"\n' +
            '                        codebase="../LiteAvSDK/LiteAVAX.cab#version=3,0,0,1"\n' +
            '                        width=' + width.toString() + "\n"  +
            '                        height=' + height.toString() + "\n" +
            '                        events="True"></object>';

        parentView.innerHTML = html;

        var player = document.getElementById(userIDPrefix + object.data.userID);
        viewTag++;
        player.viewTag = viewTag;
        player.setRenderWndSize(width, height);
        player.setRenderMode(1);
        player.setPlayerEventCallBack(onPlayEvent, viewTag);
        player.startPlay(object.data.playUrl, object.data.playType);

        //将player信息保存在gMergeStreams中，用于混流
        var playerInfo = {
            userID: object.data.userID,
            accelerateURL: object.data.playUrl,
            playerID:viewTag
        }
        gMergeStreams.push(playerInfo);

        object.success && object.success();
    }

    //停止播放流
    function stopPlay(object) {
        var player = document.getElementById(userIDPrefix + object.data.userID);
        if (!player) {
            object.fail && object.fail({errCode:-1, errMsg:"没有找到要停止播放的userID"});
            return;
        }
        
        player.stopPlay();
        var parentNode = player.parentNode;
        parentNode.removeChild(player);

        //清除流信息
        if (gMergeStreams && gMergeStreams.length > 0) {
            var newMergeStreams = [];
            gMergeStreams.forEach(function (val) {
                if (val.userID != object.data.userID) {
                    newMergeStreams.push(val);
                }
            });
            gMergeStreams = newMergeStreams;
            mergeStream(1);
        }
        object.success && object.success();
    }

    //停止所有加速流播放
    function stopAllAccPlayers() {
        if (roomInfo.pushers && roomInfo.pushers.length > 0) {
            roomInfo.pushers.forEach(function (pusher) {
                var livePlayer = document.getElementById(userIDPrefix + pusher.userID);
                if (livePlayer) {
                    deleteRemoteView({
                        data: {
                            userID: pusher.userID
                        }
                    });
                }
            });
        }
    }

    //开始推流
    function startPush(object) {
        var livePusher = getLivePusher();
        if (livePusher && accountInfo.pushURL) {
            livePusher.startPush(accountInfo.pushURL);
            startPushCallback = object;
        } else {
            console.log('推流失败:' + accountInfo.pushURL);
            object.fail && object.fail({
                errCode: -1,
                errMsg: '获取不到livePusher对象'
            });
        }
    }

    //向roomservice请求创建一个房间
    function doCreateRoom(object) {
        var args = {
            userID: accountInfo.userID,
            token: accountInfo.token
        }
        request({
            url: "create_room?" + formatParams(args),
            data: {
                userID: accountInfo.userID,
                roomInfo: object.data.roomInfo || ""
            },
            success: function(ret) {
                if (ret.data.code) {
                    console.log('请求CGI:create_room失败', ret);
                    object.fail && object.fail({errCode: ret.data.code, errMsg: '请求CGI:create_room失败:' + ret.data.message +  + '[' + ret.data.code + ']'});
                    return;
                }
                object.success && object.success(ret);
            },
            fail: object.fail
        });
    }

    //房间增加一路推流
    function addPusher(object) {

        var body = {
            roomID: roomInfo.roomID,
            userID: accountInfo.userID,
            userName: accountInfo.userName,
            userAvatar: accountInfo.userAvatar,
            pushURL: accountInfo.pushURL
        }

        var args = {
            userID: accountInfo.userID,
            token: accountInfo.token
        }

        request({
            url: "add_pusher?" + formatParams(args),
            data: body,
            success: function(ret) {
                if (ret.data.code) {
                    console.log('请求CGI:create_room失败', ret);
                    object.fail && object.fail({errCode: ret.data.code, errMsg: '请求CGI:create_room失败:' + ret.data.message +  + '[' + ret.data.code + ']'});
                    return;
                }
                object.success && object.success(ret);
            },
            fail: object.fail
        });
    }

    //获取pusher对象
    function getLivePusher() {
        var livePusher = document.getElementById(userIDPrefix + accountInfo.userID);
        if (!livePusher && accountInfo.previewDivId && accountInfo.previewDivId.length > 0) {
            console.log('accountInfo.previewDivId: ', accountInfo.previewDivId)
            var parentView = document.getElementById(accountInfo.previewDivId);
            console.log("parentView:", parentView);
            if (!parentView) {
                console.error("没有获取到推流div");
                return;
            }
            var width = parentView.offsetWidth;
            var height = parentView.offsetHeight;
    
            var html = '<object ID=' + userIDPrefix + accountInfo.userID.toString() + ' CLASSID="CLSID:01502AEB-675D-4744-8C84-9363788ED6D6"\n' +
                '                        codebase="../LiteAvSDK/LiteAVAX.cab#version=3,0,0,1"\n' +
                '                        width=' + width.toString() + "\n"  +
                '                        height=' + height.toString() + "\n" +
                '                        events="True"></object>';
            parentView.innerHTML = html;
            var livePusher = document.getElementById(userIDPrefix + accountInfo.userID);
            livePusher.setRenderWndSize(width, height);
        }
        return livePusher;
    }

    //获取所有摄像头
    function getCameras(object){
        if (!object || !object.data.previewDivId) {
            return null;
        }
        accountInfo.previewDivId = object.data.previewDivId;
        var livePusher = getLivePusher();
        var szRet = livePusher.enumCameras();
        var obj = JSON.parse(szRet);
        if (obj.code != 0) {
            return obj;
        }
        return null;
    }

    /***********************************************************************************
    * http请求
    ************************************************************************************/
    function request(object) {
        if (!serverDomain)  {
            console.error('请设置serverDomain2');
            if(typeof(object.fail) != "undefined" && object.fail != null){
                object.fail({errCode:-1, errMsg:"serverDomain为空, 请调用login接口进行设置"});
            }
            return;
        }
        httpRequest({
            url: serverDomain + object.url,
            data: object.data || {},
            method: "POST",
            success: object.success || function () {},
            fail: object.fail || function () {},
            complete: object.complete || function () {}
        })
    }

    function httpRequest(object) {
        /*
        if (isIE9Version() == true) {
            httpXDRRequest(object);
            return;
        }*/
        object= object|| {};
        object.method = (object.method|| "GET").toUpperCase();
        object.dataType = "json";
        var params = formatParams(object.data);

        //创建 - 非IE6 - 第一步
        if (window.XMLHttpRequest) {
            var xhr = new XMLHttpRequest();
        } else { //IE6及其以下版本浏览器
            var xhr = new ActiveXObject('Microsoft.XMLHTTP');
        }

        var timeout_time = typeof(object.timeout) == "undefined" ? 10000 : object.timeout;
        var timeout = false;
        var timer = setTimeout(function () {
            timeout = true;
            xhr.abort();
        }, timeout_time);
        //接收 - 第三步
        xhr.onreadystatechange = function () {
            if (xhr.readyState == 4) {
                if (timeout) {
                    object.fail && object.fail({code: -1, msg:"请求超时"});
                }
                var status = xhr.status;
                clearTimeout(timer);
                if (status >= 200 && status < 300) {
                    var jsonObj = JSON.parse(xhr.responseText);
                    object.success && object.success({status: status, data:jsonObj});
                } else {
                    object.fail && object.fail({code:status, msg:xhr.message});
                }

                object.complete && object.complete();
            }
        }

        //连接 和 发送 - 第二步
        if (object.method == "GET") {
            xhr.open("GET", object.url + "?" + params, true);
            xhr.send(null);
        } else if (object.method == "POST") {
            xhr.open("POST", object.url, true);
            //设置表单提交时的内容类型
            xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
            xhr.send(params);
        }
    }

    //IE8~9下的跨域请求兼容，xhr在IE9不支持跨域。
    function httpXDRRequest(object) {
        object = object || {};
        object.method = (object.method || "GET").toUpperCase();
        object.dataType = "json";
        var params = formatXDRParams(object.data);
        //创建 - 非IE6 - 第一步
        var xdr = new XDomainRequest();
        xdr.timeout = typeof (object.timeout) == "undefined" ? 10000 : object.timeout;
        var timeout = false;
        xdr.ontimeout = function () {
            timeout = true;
            xdr.abort();
            console.log("ontimeout", xdr);
        };
        xdr.onprogress = function () { };
        xdr.onerror = function () {
            console.log("onerror", xdr);
        };
        //接收 - 第三步
        xdr.onload = function () {
            //alert(xdr.responseText);
            var status = xdr.status;
            var jsonObj = JSON.parse(xdr.responseText);
            object.success && object.success({ status: 200, data: jsonObj });
            object.complete && object.complete();
        }

        //连接 和 发送 - 第二步
        if (object.method == "GET") {
            xdr.open("GET", object.url + "?" + params, true);
            xdr.send(null);
        } else if (object.method == "POST") {
            // xdr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
            xdr.open("POST", object.url, true);
            //设置表单提交时的内容类型
            var paramsss = "{\"userIDPrefix\":\"IE(ActiveX)\",\"v\":\"12546423232123123\"}";
            console.log(params);
            xdr.send(params);
        }
    }

    //格式化参数
    function formatXDRParams(data) {
        var jsonStrRet;
        jsonStrRet="{";
        for (var name in data) {
            if (typeof (data[name]) ==typeof ("123")){
                jsonStrRet += "\"" + name + "\"" +  ":" + "\"" + data[name] + "\",";
            }
            else {
                jsonStrRet += "\"" + name + "\"" +  ":"  + data[name] + ",";
            }
        }
        jsonStrRet = jsonStrRet.substring(0,jsonStrRet.lastIndexOf(','));
        jsonStrRet += "}";
        return jsonStrRet;
    }

    //格式化参数
    function formatParams(data) {
        var arr = [];
        for (var name in data) {
            arr.push(encodeURIComponent(name) + "=" + encodeURIComponent(data[name]));
        }
        arr.push(("v=" + Math.random()).replace(".",""));
        return arr.join("&");
    }

    /**
    * 检测是否是ie9
    *
    */
    function isIE9Version() {
        var browser = navigator.appName
        var b_version = navigator.appVersion
        var version = b_version.split(";");
        var trim_Version = version[1].replace(/[ ]/g, "");
        if (browser == "Microsoft Internet Explorer" && trim_Version == "MSIE9.0") {
            return true;
        }
        return false;
    }


    /*************************************
     * IM相关接口
     *************************************/
    /**
     * [loginIM 登录IM]
     * @param {options}
     *   data: {
     *   	roomID: 房间ID
     *   }
     *   success: 成功回调
     *   fail: 失败回调
     */
    function loginIM(options) {
        roomInfo.isDestory = false;
        // 初始化设置参数
        webimhandler.init({
            accountMode: accountInfo.accountMode,
            accountType: accountInfo.accountType,
            sdkAppID: accountInfo.sdkAppID,
            avChatRoomId: options.roomID,
            selType: webim.SESSION_TYPE.GROUP,
            selToID: options.roomID,
            selSess: null //当前聊天会话
        });
        //当前用户身份
        var userInfo = {
            'sdkAppID': accountInfo.sdkAppID, //用户所属应用id,必填
            'appIDAt3rd': accountInfo.sdkAppID, //用户所属应用id，必填
            'accountType': accountInfo.accountType, //用户所属应用帐号类型，必填
            'identifier': accountInfo.userID, //当前用户ID,必须是否字符串类型，选填
            'identifierNick': accountInfo.userName, //当前用户昵称，选填
            'userSig': accountInfo.userSig, //当前用户身份凭证，必须是字符串类型，选填
        };
        //监听（多终端同步）群系统消息方法，方法都定义在demo_group_notice.js文件中
        var onGroupSystemNotifys = {
            // 群被解散(全员接收)
            "5": function(notify) {
                roomInfo.isDestory = true;
                console.log('群被解散');
                event.onRoomClosed();
            },
            "11": webimhandler.onRevokeGroupNotify, //群已被回收(全员接收)
            // 用户自定义通知(默认全员接收)
            "255": function(notify) {
                console.error('收到系统通知：',notify.UserDefinedField);
                var content = JSON.parse(notify.UserDefinedField);
                if(content && content.cmd == 'notifyPusherChange') {
                    mergePushers();
                }
            }
        };

        //监听连接状态回调变化事件
        var onConnNotify = function (resp) {
            switch (resp.ErrorCode) {
                case webim.CONNECTION_STATUS.ON:
                    console.log.warn('webim连接状态正常...');
                    break;
                case webim.CONNECTION_STATUS.OFF:
                    console.log('webim连接已断开，无法收到新消息，请检查下你的网络是否正常');
                    break;
                default:
                    console.log('webim未知连接状态,status=' + resp.ErrorCode);
                    break;
            }
        };

        //监听事件
        var listeners = {
            "onConnNotify": webimhandler.onConnNotify, //选填
            "onBigGroupMsgNotify": function (msg) {
                webimhandler.onBigGroupMsgNotify(msg, function (msgs) {
                    receiveMsg(msgs);
                }, function(datas){
                    //收到白板数据
                    console.log("LiveRoom callback --> 收到白板数据")
                    onSketchpadData(datas);
                } )
            }, //监听新消息(大群)事件，必填
            "onMsgNotify": function (newMsgList) { //监听新消息(私聊(包括普通消息和全员推送消息)，普通群(非直播聊天室)消息)事件，必填
                webimhandler.onMsgNotify(newMsgList, function(msg) {
                    recvC2CMsg(msg);
                });
            },
            "onGroupSystemNotifys": onGroupSystemNotifys, //监听（多终端同步）群系统消息事件，必填
            "onGroupInfoChangeNotify": webimhandler.onGroupInfoChangeNotify,
            // 'onKickedEventCall': self.onKickedEventCall // 踢人操作
        };

        //其他对象，选填
        var others = {
            'isAccessFormalEnv': true, //是否访问正式环境，默认访问正式，选填
            'isLogOn': false //是否开启控制台打印日志,默认开启，选填
        };

        if (accountInfo.accountMode == 1) { //托管模式
            webimhandler.sdkLogin(userInfo, listeners, others, 0, afterLoginIM, options);
        } else { //独立模式
            //sdk登录
            webimhandler.sdkLogin(userInfo, listeners, others, 0, afterLoginIM, options);
        }
    }
    function afterLoginIM(options) {
        if(options.errCode) {
            // webim登录失败
            console.log('webim登录失败:');
            options.callback.fail && options.callback.fail({
                errCode: -2,
                errMsg: '登录失败'
            });
            return;
        }
        // webim登录成功
        console.log('webim登录成功');
        if (roomInfo.roomID) {
            webimhandler.applyJoinBigGroup(roomInfo.roomID, afterJoinBigGroup, {
                success: options.callback.success,
                fail: options.callback.fail
            });
        } else {
            options.callback.success && options.callback.success({
                errCode: 0,
                errMsg: ''
            });
        }
    }
    function afterJoinBigGroup(options) {
        if(options.errCode) {
            console.log('进入IM房间失败: ');
            options.callback.fail && options.callback.fail({
                errCode: -2,
                errMsg: '登录失败'
            });
            return;
        }
        console.log('进入IM房间成功: ',roomInfo.roomID);
    }

    /**
     * [receiveMsg 接收消息处理]
     * @param {options}
     *
     * @return event.onRecvRoomTextMsg
     *   roomID: 房间ID
     *   userID: 用户ID
     *   userName: 用户昵称
     *   userAvatar: 用户头像
     *   message: 文本消息
     *   time: 消息时间
     */
    function receiveMsg(msg) {
        if (!msg.content) {  return; }
        console.log('IM消息: ',JSON.stringify(msg));
        var time = new Date();
        var h = time.getHours()+'', m = time.getMinutes()+'', s = time.getSeconds()+'';
        h.length == 1 ? (h='0'+h) : '';
        m.length == 1 ? (m='0'+m) : '';
        s.length == 1 ? (s='0'+s) : '';
        time = h + ':' + m + ':' + s;
        msg.time = time;

        if(msg.fromAccountNick == '@TIM#SYSTEM') {
            msg.fromAccountNick = '';
            msg.content = msg.content.split(';');
            msg.content = msg.content[0];
        } else {
            var contentObj,newContent;
            newContent = msg.content.split('}}');
            contentObj = JSON.parse(newContent[0] + '}}');
            if(contentObj.cmd == 'CustomTextMsg') {
                msg.userName = contentObj.data.nickName;
                msg.userAvatar = contentObj.data.headPic;
                var content = '';
                for(var i = 1; i < newContent.length; i++) {
                    if(i == newContent.length - 1)
                        content += newContent[i];
                    else content += newContent[i] + '}}';
                }
                msg.content = content;
                event.onRecvRoomTextMsg && event.onRecvRoomTextMsg({
                    roomID: roomInfo.roomID,
                    userID: msg.fromAccountNick,
                    userName: msg.userName,
                    userAvatar: msg.userAvatar,
                    message: msg.content,
                    time: msg.time
                });
            } else if (contentObj.cmd == 'CustomCmdMsg') {
                msg.userName = contentObj.data.nickName;
                msg.userAvatar = contentObj.data.headPic;
                msg.cmd = contentObj.data.cmd;
                var content = '';
                for(var i = 1; i < newContent.length; i++) {
                    if(i == newContent.length - 1)
                        content += newContent[i];
                    else content += newContent[i] + '}}';
                }
                msg.content = content;
                event.onRecvRoomCustomMsg && event.onRecvRoomCustomMsg({
                    roomID: roomInfo.roomID,
                    userID: msg.fromAccountNick,
                    userName: msg.userName,
                    userAvatar: msg.userAvatar,
                    cmd: msg.cmd,
                    message: msg.content,
                    time: msg.time
                });
            }
        }
        
    };

    function recvC2CMsg(msg) {
        console.log("收到C2C消息:", JSON.stringify(msg));
        var contentObj = JSON.parse(msg.content);
        if (contentObj) {
            if (contentObj.cmd == 'linkmic') {
                if (contentObj.data.type && contentObj.data.type == 'request') {
                    event.onRecvJoinPusherRequest({
                        userID: msg.fromAccountNick,
                        userName: contentObj.data.userName,
                        userAvatar: contentObj.data.userAvatar
                    })
                } else if (contentObj.data.type && contentObj.data.type == 'response') {
                    if (contentObj.data.result == 'accept') {
                        requestJoinCallback && requestJoinCallback({
                            errCode: 0,
                            errMsg: ''
                        });
                    } else if (contentObj.data.result == 'reject') {
                        requestJoinCallback && requestJoinCallback({
                            errCode: -999,
                            errMsg: '主播拒绝了你的请求'
                        });
                    }
                } else if (contentObj.data.type && contentObj.data.type == 'kickout') {
                    event.onKickOut && event.onKickOut({
                        roomID: contentObj.data.roomID
                    });
                }
            } else {
                event.onRecvC2CCustomMsg && event.onRecvC2CCustomMsg({
                    userID: msg.fromAccountNick,
                    userName: contentObj.data.userName,
                    userAvatar: contentObj.data.userAvatar,
                    cmd: contentObj.cmd,
                    message: contentObj.data.msg
                });
            }
        }
    }

    function onSketchpadData(data){
        console.log("LiveRoom event --> 回调白板数据")
        event.onSketchpadData && event.onSketchpadData(data);
    }
    /**
 * [mergePushers pushers merge操作]
 * @param {options}
 *
 * @return event.onPusherJoin 
 *   pushers: 进房人员列表
 *   
 * @return event.onPhserQuit
 *   pushers: 退房人员列表
 */
function mergePushers() {
	getPushers({
        data: {
            roomID: roomInfo.roomID
        },
		success: function(ret) {
            ret = ret.data;
			/**
			 * enterPushers：新进推流人员信息
			 * leavePushers：退出推流人员信息
			 * ishave：用于判断去重操作
			 */
			var enterPushers = [],leavePushers = [],ishave = 0;
			console.log('去重操作');
			console.log('旧', JSON.stringify(roomInfo.pushers));
            console.log('新',JSON.stringify(ret.pushers));
            console.log('用户信息:', JSON.stringify(accountInfo));
			ret.pushers && ret.pushers.forEach(function(val1){
				ishave = 0;
				roomInfo.pushers && roomInfo.pushers.forEach(function(val2) {
					if(val1.userID == val2.userID) {
						ishave = 1;
					}
				});
				if(!ishave && val1.userID != accountInfo.userID)
					enterPushers.push(val1);
				ishave = 0;
			});
			roomInfo.pushers && roomInfo.pushers.forEach(function(val1) {
				ishave = 0;
			    ret.pushers && ret.pushers.forEach(function(val2) {
					if(val1.userID == val2.userID) {
						ishave = 1;
					}
				});
				if(!ishave)
					leavePushers.push(val1);
				ishave = 0;
			});
			// 重置roomInfo.pushers
			roomInfo.pushers = ret.pushers;
			// 通知有人进入房间
			if(enterPushers.length) {
                console.log('进房:', JSON.stringify(enterPushers));
				event.onPusherJoin({
					pushers: enterPushers
				});

                if (roomInfo.roomCreator && roomInfo.roomCreator == accountInfo.userID) {
                    //大主播调整画质
                    setVideoQualityImpl(VIDEO_QUALITY.LINKMIC_MAIN_PUSHER, ratioType);
                }
			}
			// 通知有人退出房间
			if(leavePushers.length) {
                console.log('退房:', JSON.stringify(leavePushers));
				event.onPusherQuit({
					pushers: leavePushers
                });

                if (roomInfo.roomCreator && roomInfo.roomCreator == accountInfo.userID) {
                    if (!roomInfo.pushers || roomInfo.pushers.length <= 1) {
                        //大主播恢复画质
                        setVideoQualityImpl(videoQuality, ratioType);
                    }
                }
            }
		},
		fail: function(ret) {
			// event.onRoomClosed({
			// 	errCode: ret.errCode,
			// 	errMsg: ret.errMsg
			// });
		}
	});
};


function getPushers(object) {
    var args = {
        userID: accountInfo.userID,
        token: accountInfo.token
    }
    //获取房间信息
    request({
        url: 'get_pushers?' + formatParams(args),
        data: {
            roomID: object.data.roomID
        },
        success: function (ret) {
            if (ret.data.code) {
                console.log('请求CGI:get_pushers失败', ret);
                object.fail && object.fail({errCode: ret.data.code, errMsg: '请求CGI:get_pushers失败:' + ret.data.message +  + '[' + ret.data.code + ']'});
                return;
            }
            console.log("房间信息：", JSON.stringify(ret));
            object.success && object.success(ret);
        },
        fail: object.fail
    }); 
}

/**
 * 
 * @param {Int} retryCount
 */
function mergeStream(retryCount) {
    if (accountInfo.userID != roomInfo.roomCreator) {
        //大主播才能混流
        return;
    }
    var mergeStreams = [];
    console.log("混流信息:", JSON.stringify(gMergeStreams));
    if (gMergeStreams && gMergeStreams.length > 0) {
        gMergeStreams.forEach(function (val) {
            if (val.width && val.height) {
                //获取流id
                var streamID = getStreamIDByStreamUrl(val.accelerateURL);
                if (streamID) {
                    mergeStreams.push({
                        userID: val.userID,
                        streamID: streamID,
                        width: val.width,
                        height: val.height
                    });
                }
            }
        });
    }
    
    if (roomInfo.pushers && roomInfo.pushers.length > 0) {
        roomInfo.pushers.forEach(function (val) {
            if (val.userID == roomInfo.roomCreator) {
                bigAnchorStreamID = getStreamIDByStreamUrl(val.accelerateURL);
            }
        });
    }

    sendStreamMergeRequest(retryCount, mergeStreams);
}

function getStreamIDByStreamUrl(streamUrl) {
    if (!streamUrl) {
        return null;
    }
    //推流地址格式: rtmp://8888.livepush.myqcloud.com/path/8888_test_12345?txSecret=aaa&txTime=bbb
    //拉流地址格式: rtmp://8888.livepush.myqcloud.com/path/8888_test_12345
    //             http://8888.livepush.myqcloud.com/path/8888_test_12345.flv
    //             http://8888.livepush.myqcloud.com/path/8888_test_12345.m3u8

    var subStr = streamUrl;
    var index = subStr.indexOf('?');
    if (index >= 0) {
        subStr = subStr.substring(0, index);
    }
    if (!subStr) {
        return null;
    }
    index = subStr.lastIndexOf('/');
    if (index >= 0) {
        subStr = subStr.substring(index + 1);
    }
    if (!subStr) {
        return null;
    }
    index = subStr.indexOf('.');
    if (index >= 0) {
        subStr = subStr.substring(0, index);
    }
    if (!subStr) {
        return null;
    }
    return subStr;
}

function sendStreamMergeRequest(retryCount, mergeStreams) {
    if (retryCount < 0) {
        return;
    }

    var mergeInfo = createMergeInfo(mergeStreams);
    console.log('混流信息:', JSON.stringify(mergeInfo));

    doMergeRequest(mergeInfo, function (ret) {
        if (ret) {
            console.log('混流成功');
        } else {
            console.log('混流失败');
            setTimeout( function() {
                retryCount--;
                sendStreamMergeRequest(retryCount, mergeStreams);
            }, 2000);
        }
    });
}

function doMergeRequest(mergeInfo, callback) {
    var args = {
        userID: accountInfo.userID,
        token: accountInfo.token
    }

    request({
        url: 'merge_stream?' + formatParams(args),
        data: {
            userID: accountInfo.userID,
            roomID: roomInfo.roomID,
            mergeParams: JSON.stringify(mergeInfo)
        },
        success: function (ret) {
            if (ret.data.code || ret.data.result.code) {
                console.error('混流失败:', JSON.stringify(ret));
                callback(false);
                return;
            }
            callback(true);
        },
        fail: function (ret) {
            callback(false);
        }
    })
}

function createMergeInfo(mergeStreams) {
    console.log("混流原始信息:", JSON.stringify(mergeStreams));
    var canvasWidth = 640, canvasHeight = 640;
    var bigAnchorWidth = 640, bigAnchorHeight = 640;
    switch (videoQuality) {
        case VIDEO_QUALITY.HIGH:
            if (ratioType == RATIO_TYPE.TYPE_WIDE) {
                // bigAnchorWidth = 640;
                // bigAnchorHeight = 480;
                bigAnchorWidth = 640;
                bigAnchorHeight = 360;
            } else {
                // bigAnchorWidth = 480;
                // bigAnchorHeight = 640;
                bigAnchorWidth = 360;
                bigAnchorHeight = 640;
            }
            break;
        case VIDEO_QUALITY.SUPER:
            if (ratioType == RATIO_TYPE.TYPE_WIDE) {
                // bigAnchorWidth = 960;
                // bigAnchorHeight = 720;
                bigAnchorWidth = 960;
                bigAnchorHeight = 540;
            } else {
                // bigAnchorWidth = 720;
                // bigAnchorHeight = 960;
                bigAnchorWidth = 540;
                bigAnchorHeight = 960;
            }
            berak;
        default:
            if (ratioType == RATIO_TYPE.TYPE_WIDE) {
                // bigAnchorWidth = 480;
                // bigAnchorHeight = 360;
                bigAnchorWidth = 480;
                bigAnchorHeight = 272;
            } else {
                // bigAnchorWidth = 360;
                // bigAnchorHeight = 480;
                bigAnchorWidth = 272;
                bigAnchorHeight = 480;
            }
            break;
    }

    // //计算画布大小，画布上部分为大主播画面，下部分为小主播画面,最多放置三个,小主播画面宽高比为2:3
    // var smallAnchorWidth = Math.floor(bigAnchorWidth / 6) * 2;
    // var smallAnchorHeight = Math.floor(smallAnchorWidth * 3 / 4) * 2;
    // 计算画布大小，画布上部分为大主播画面，下部分为小主播画面,最多放置三个,小主播画面宽高比为1:1
    var smallAnchorWidth = Math.floor(bigAnchorWidth / 6) * 2;
    var smallAnchorHeight = smallAnchorWidth;
    canvasWidth = bigAnchorWidth;
    canvasHeight = bigAnchorHeight + smallAnchorHeight;

    //组装混流JSON结构体
    var streamInfoArray = [];
    if (mergeStreams && mergeStreams.length > 0) {
        //画布
        var mainViewInfo = {
            input_stream_id: bigAnchorStreamID || '',
            layout_params: {
                image_layer: 1,
                image_width: canvasWidth,
                image_height: canvasHeight,
                input_type: 3
            }
        }
        streamInfoArray.push(mainViewInfo);
        
        //大主播
        var bigAnchorInfo = {
            input_stream_id: bigAnchorStreamID || '',
            layout_params: {
                image_layer: 2,
                image_width: bigAnchorWidth,
                image_height: bigAnchorHeight,
                location_x: 0,
                location_y: 0
            }
        }
        streamInfoArray.push(bigAnchorInfo);

        //小主播
        var subLocationX = 0;
        var subLocationY = bigAnchorHeight;
        if (mergeStreams && mergeStreams.length > 0) {
            var layerIndex = 0
            mergeStreams.forEach(function (val) {

                if (val.width && val.height) {
                    var cropWidth = val.width, cropHeight = val.height;
                    // //2:3裁剪
                    // if (val.width * 3 < val.height * 2) {
                    //     cropWidth = val.width;
                    //     cropHeight = Math.round(cropWidth * 3 / 4) * 2;
                    // } else {
                    //     cropHeight = val.height;
                    //     cropWidth = Math.round(cropHeight / 3)  * 2;
                    // }
                    //1:裁剪
                    if (val.width < val.height ) {
                        cropWidth = val.width;
                        cropHeight = cropWidth;
                    } else {
                        cropHeight = val.height;
                        cropWidth = cropHeight;
                    }

                    //组装JSON
                    var smallAchorInfo = {
                        input_stream_id: val.streamID,
                        layout_params: {
                            image_layer: layerIndex + 3,
                            image_width: (layerIndex>=2?bigAnchorWidth-smallAnchorWidth*2:smallAnchorWidth),
                            image_height: smallAnchorHeight,
                            location_x: subLocationX + layerIndex * smallAnchorWidth,
                            location_y: subLocationY
                        },
                        crop_params: {
                            crop_width: cropWidth,
                            crop_height: cropHeight,
                            crop_x: Math.round((val.width - cropWidth) / 4) * 2,
                            crop_y: Math.round((val.height - cropHeight) / 4) *2
                        }
                    }
                    streamInfoArray.push(smallAchorInfo);
                    layerIndex++;
                }
            });
        }
    } else {
        var bigAnchorInfo = {
            input_stream_id: bigAnchorStreamID || '',
            layout_params: {
                image_layer: 1
            }
        }
        streamInfoArray.push(bigAnchorInfo);
    }

    var para = {
        app_id: accountInfo.sdkAppID.toString(),
        interface: 'mix_streamv2.start_mix_stream_advanced',
        mix_stream_session_id: bigAnchorStreamID,
        output_stream_id: bigAnchorStreamID,
        input_stream_list: streamInfoArray
    }

    var interfaceObj = {
        interfaceName: 'Mix_StreamV2',
        para: para
    }

    var reqParam = {
        timestamp: Math.round((Date.now() / 1000)),
        eventId: Math.round((Date.now() / 1000)),
        interface: interfaceObj
    }

    return reqParam;
}

    /************************************
     * 心跳
     ***********************************/
    /**
     * [pusherHeartBeat 推流者心跳]
     * @param {options}
     */
    function pusherHeartBeat(options) {
        if(options) {
            setTimeout(function(){
                proto_pusherHeartBeat();
            },3000);
        }
        if(heart) {
            setTimeout(function(){
                proto_pusherHeartBeat();
                pusherHeartBeat();
            },7000);
        }
    }
    function proto_pusherHeartBeat(){
        // console.log('心跳请求');
        var args = {
            userID: accountInfo.userID,
            token: accountInfo.token
        }
        request({
            url: 'pusher_heartbeat?' + formatParams(args),
            data: {
                roomID: roomInfo.roomID,
                userID: accountInfo.userID
            },
            success: function(ret) {
                if(ret.data.code) {
                    console.log('心跳失败：', JSON.stringify(ret));
                    return;
                }
                // console.log('心跳成功',ret);
            },
            fail: function(ret) {
                console.log('心跳请求失败：', JSON.stringify(ret));
            }
        });
    }

    /**
     * [stopPusherHeartBeat 停止推流者心跳]
     * @param {options}
     */
    function stopPusherHeartBeat() {
        heart = false;
    }

    var bInStatus = false;
    var onPushEvent = function (msg) {
        var obj = JSON.parse(msg);
        if (obj.eventId != 200001)
             console.log("onPushEvent.PusherID:" + obj.objectId.toString() + " eventId:"+ obj.eventId.toString());
    
        switch (obj.eventId) {
            case 1002: {
                console.log("推流成功 ,1002");
                startPushCallback && startPushCallback.success && startPushCallback.success();
                break;
            }
            case -1301: {
                if(bInStatus == true) return;
                bInStatus = true;
                console.log("打开摄像头失败");
                alert("打开摄像头失败,请尝试重新进房间");
                exitRoom({});
                //updatePageQuitRoomStatus();
                startPushCallback && startPushCallback.fail && startPushCallback.fail({
                    errCode: -999,
                    errMsg: '打开摄像头失败'
                });
                bInStatus = false;
                break;
            }
            case -1302: {
                if(bInStatus == true) return;
                bInStatus = true;
                console.log("打开麦克风失败");
                alert("打开麦克风失败, 请尝试重新进房间");
                exitRoom({});
                //updatePageQuitRoomStatus();
                startPushCallback && startPushCallback.fail && startPushCallback.fail({
                    errCode: -999,
                    errMsg: '打开麦克风失败'
                });
                bInStatus = false;
                break;
            }
            case -1307: {
                if(bInStatus == true) return;
                bInStatus = true;
                console.log("推流连接断开");
                alert("推流连接断开,请尝试重新进房间");
                exitRoom({});
                //updatePageQuitRoomStatus();
                event.onError && event.onError({
                    errCode: -1307,
                    errMsg: '推流连接断开'
                });
                bInStatus = false;
                break;
            }
            case -1308: {
                if(bInStatus == true) return;
                bInStatus = true;
                console.log("当前摄像头被占用, 请尝试重新进房间");
                alert("当前摄像头被占用, 请尝试重新进房间");
                exitRoom({
                    success: function (ret) {},
                    fail: function (ret) {}
                });
                if(startPushCallback){
                    startPushCallback.fail && startPushCallback.fail({
                        errCode: -999,
                        errMsg: '当前摄像头被占用, 请尝试重新进房间'
                    });
                }
                else{
                    event.onError && event.onError({
                        errCode: -1308,
                        errMsg: '当前摄像头被占用, 请尝试重新进房间'
                    });
                }
                bInStatus = false;
                break;
            }

            case 3005: {
                if(bInStatus == true) return;
                bInStatus = true;
                console.log("30s没流数据，推流连接断开");
                alert("30s没流数据，推流连接断开,请尝试重新进房间");
                exitRoom({
                    success: function (ret) {},
                    fail: function (ret) {}
                });
                //updatePageQuitRoomStatus();
                event.onError && event.onError({
                    errCode: 3005,
                    errMsg: '30s没流数据，推流连接断开,请尝试重新进房间'
                });
                bInStatus = false;
                break;
            }
        }
    };
    
    var onPlayEvent = function (msg) {
        var obj = JSON.parse(msg);
        if (parseInt(obj.eventId) != 200002) {
            console.log("onPlayEvent.PlayId: " + obj.objectId.toString() + " eventId:"+ obj.eventId.toString());
        } else {
            var needMergeStream = false;
            var playerID = parseInt(obj.objectId);
            if (gMergeStreams && gMergeStreams.length > 0) {
                gMergeStreams.forEach(function (val) {
                    if (val.playerID == playerID) {
                        if (obj.paramCnt != 0) {
                            for (var i = 0; i < obj.paramCnt; ++i) {
                                if (obj.paramlist[i].key == "VIDEO_WIDTH") {
                                    if (!val.width || val.width != obj.paramlist[i].value) {
                                        needMergeStream = true;
                                        val.width = obj.paramlist[i].value;
                                    }
                                }
                                if (obj.paramlist[i].key == "VIDEO_HEIGHT") {
                                    if (!val.height || val.height != obj.paramlist[i].value) {
                                        needMergeStream = true;
                                        val.height = obj.paramlist[i].value;
                                    }
                                }
                            }
                        }
                    }
                });
            }

            if (needMergeStream && accountInfo.userID == roomInfo.roomCreator) {
                //大主播才能混流
                mergeStream(5);
            }
        }
    };

    function sendC2CCustomMsg(object) {
        var body = {
            cmd: object.cmd,
            data: {
                userID: accountInfo.userID,
                userName: accountInfo.userName,
                userAvatar: accountInfo.userAvatar,
                msg: object.msg || ''
            }
        }
        var msg = {
            data: JSON.stringify(body)
        }
        webimhandler.sendC2CCustomMsg(object.toUserID?object.toUserID:roomInfo.roomCreator, msg, function (ret) {
            if (ret && ret.errCode) {
                console.log('请求连麦失败:', JSON.stringify(ret));
                object.fail && object.fail(ret);
                return;
            }
            object.success && object.success({});
        });
    }

    return {
        login: login,
        logout: logout,
        setLiveRoomListener: setLiveRoomListener,

        createRoom: createRoom,
        enterRoom: enterRoom,
        exitRoom: exitRoom,
        getRoomList: getRoomList,
        joinPusher: joinPusher,
        quitPusher: quitPusher,
        requestJoinPusher: requestJoinPusher,
        acceptJoinPusher: acceptJoinPusher,
        rejectJoinPusher: rejectJoinPusher,
        kickoutSubPusher: kickoutSubPusher,

        startLocalPreview: startLocalPreview,
        stopLocalPreview: stopLocalPreview,
        //switchToBackground: switchToBackground,
        //switchToForeground: switchToForeground,
        switchCamera: switchCamera,
        //setMicVolume: setMicVolume,
        //setMute: setMute,
        addRemoteView: addRemoteView,
        deleteRemoteView: deleteRemoteView,

        sendRoomTextMsg: sendRoomTextMsg,
        sendRoomCustomMsg: sendRoomCustomMsg,
        sendSketchpadData: sendSketchpadData,        
        //setCustomInfo: setCustomInfo,
        //decCustomInfo: decCustomInfo,
        //incCustomInfo: incCustomInfo,

        //setBGMVolume: setBGMVolume,
        //setBGMNofify: setBGMNofify,
        //getMusicDuration: getMusicDuration,
        //playBGM: playBGM,
        //stopBGM: stopBGM,
        //pauseBGM: pauseBGM,
        //resumeBGM: resumeBGM,

        setBeautyFilter: setBeautyFilter,
        setVideoQuality: setVideoQuality,
        //setZoom: setZoom,
        //setMirror: setMirror,
        //setExposureCompensation: setExposureCompensation,
        //setRenderRotation: setRenderRotation,
        //setFilter: setFilter,
        //setMotionTmpl: setMotionTmpl,
        //setGreenScreenFile: setGreenScreenFile,
        //setEyeScaleLevel: setEyeScaleLevel,
        //setFaceSlimLevel: setFaceSlimLevel,
        //setFaceVLevel: setFaceVLevel,
        //setSpecialRatio: setSpecialRatio,
        //setFaceShortLevel: setFaceShortLevel,
        //setChinLevel: setChinLevel,
        //setNoseSlimLevel: setNoseSlimLevel,
        //setReverb: setReverb,
        //setPauseImage: setPauseImage,
        getCameras:getCameras,
        sendC2CCustomMsg: sendC2CCustomMsg,
        getAudienceList: getAudienceList
    }
})()
